unit uESInBound;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, Crt,
  SynCommons,
  SynWinSock,
  SynCrtSock,
  SynBidirSock,
  SynLog,
  mORMot,
  lNet,
  uBusinessInterface;

type
  TNotifyDataEvent = procedure(const Data: RawUTF8) of object;

  TTCPClientThread = class(TSynThread)  //TSynThread
  private
    fClient: TCrtSocket;             //TIdTCPClient, TAsynchClient, TCrtSocket
    FData: string;
    FOnData: TNotifyDataEvent;

    procedure DataReceived;
  protected
    procedure Execute; override;
  public
    constructor Create(AClient: TCrtSocket); reintroduce;
    property OnData: TNotifyDataEvent read FOnData write FOnData;
  end;

  TESInBound = class(TInterfacedObject, IESInBound)
  private
    //FOnFSData: TNotifyDataEvent;
    FListener : TTCPClientThread;
    FTCPClient: TCrtSocket;
    procedure FSDataReceived(const Data: RawUTF8);
  protected
    procedure DoOnConnected;
    procedure DoOnDisconnected;
  public
    constructor Create; reintroduce;
    destructor Destroy; override;
    function IsAlive: Boolean;
    procedure SendData(const AMessage: RawUTF8);
    //property OnFSData: TNotifyDataEvent read FOnFSData write FOnFSData;

    procedure ForTest(aFSMessage: string);
  end;

implementation

{TTCPClientThread}

constructor TTCPClientThread.Create(AClient: TCrtSocket);
begin
  FClient := AClient;
  //FreeOnTerminate := True;

  // CreateSuspended:如果把这个参数设为False，那么当调用Create()之后，Execute()会被自动调用，
  // 也就是自动地执行线程代码。如果该参数设为True，这样创建了线程，但是线程创建完成之后是挂起的，
  // 需要调用TThread的Start()来唤醒线程执行。
  inherited Create(True);
end;

procedure TTCPClientThread.Execute;
begin
  while not Terminated do begin
    FData := FClient.SockReceiveString;
    if (Length(FData)>0) and Assigned(FOnData) then begin
      //Queue(@DataReceived);
      Synchronize(@DataReceived)
      //TSQLLog.Add.Log(sllInfo, '-------------------TTCPClientThread.Execute--------------------'+FData+LineEnding);
    end;
  end;
end;

procedure TTCPClientThread.DataReceived;
begin
  //if (FData <> '') and Assigned(FOnData) then FOnData(FData);
  FOnData(FData);
end;

{ TESInBound }

procedure TESInBound.FSDataReceived(const Data: RawUTF8);
begin
  //if (Data = '') then exit;
  //FOnFSData(Data);
  TSQLLog.Add.Log(sllInfo, '-------------------Event Socket Message--------------------'+LineEnding);
  TSQLLog.Add.Log(sllInfo, Data+LineEnding);
  TSQLLog.Add.Log(sllInfo, '-------------------Event Socket Message--------------------'+LineEnding);
end;

procedure TESInBound.DoOnConnected;
begin
  FTCPClient:= TCrtSocket.Create();
  //FTCPClient.Open('172.10.0.213', '8021');
  FTCPClient.Open('192.168.0.51', '8021');
  try
    FListener := TTCPClientThread.Create(FTCPClient);
    FListener.OnData := @FSDataReceived;
    FListener.Start;
  except
    FTCPClient.Close;
    raise;
  end;
  if FTCPClient.SockConnected then begin
    FTCPClient.SockSendFlush('auth ClueCon'+LineEnding+LineEnding);
    FTCPClient.SockSendFlush('log 7'+LineEnding+LineEnding);
    FTCPClient.SockSendFlush('event json ALL'+LineEnding+LineEnding);
    FTCPClient.SockSendFlush('api originate user/1001 &echo'+LineEnding+LineEnding);
  end;
end;

procedure TESInBound.DoOnDisconnected;
begin
  if Assigned(FListener) then begin
    FListener.Terminate;
    try
      FTCPClient.Close;            // 关闭并释放连接（通过 Destroy 调用）
    finally
      if Assigned(FListener) then begin
        FListener.WaitFor;
        FreeAndNil(FListener);
      end;
    end;
  end;
end;

constructor TESInBound.Create;
begin
  inherited;
  //FTCPClient:= TCrtSocket.Create();
  //DoOnConnected;
end;

destructor TESInBound.Destroy;
begin
  //DoOnDisconnected;
  //FTCPClient.Free;
  inherited;
end;

function TESInBound.IsAlive: Boolean;
begin
  Result := (FListener <> nil) and (not FListener.Finished{FListener.Terminated});
end;

procedure TESInBound.SendData(const AMessage: RawUTF8);
begin
  try
    //Socket.Write(Char.SOH + AMessage.AsXmlDataString([]) + Char.EOT, IndyTextEncoding_UTF8);
    FTCPClient.SockSendFlush(AMessage+LineEnding+LineEnding);
  except
    //Disconnect;
    DoOnDisconnected;
    // optional: re-raise...
  end;
end;

procedure TESInBound.ForTest(aFSMessage: string);
begin
  DoOnConnected;
  //SendMessageTo(aFSMessage);
end;

end.

